package com.liuhuanss.voiceprint.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.liuhuanss.voiceprint.config.VoiceprintConfig;
import com.liuhuanss.voiceprint.util.HttpUtil;
import com.liuhuanss.voiceprint.util.AudioUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * 声纹识别服务类
 * 
 * @author liuhuanss
 * @version 1.0
 */
@Service
@Slf4j
public class VoiceprintService {

    @Autowired
    private VoiceprintConfig voiceprintConfig;
    
    @Autowired
    private HttpUtil httpUtil;
    
    @Autowired
    private AudioUtil audioUtil;

    /**
     * 创建特征库
     * 
     * @param groupId 组ID
     * @return 创建结果
     */
    public Map<String, Object> createFeatureGroup(String groupId) {
        return createGroup(groupId);
    }
    
    /**
     * 创建组（特征库）
     * 
     * @param groupId 组ID
     * @return 创建结果
     */
    public Map<String, Object> createGroup(String groupId) {
        try {
            log.info("开始创建特征库，组ID: {}", groupId);
            
            String params = buildCreateGroupParams(groupId);
            String response = httpUtil.doPost(
                voiceprintConfig.getRequestUrl(),
                voiceprintConfig.getAppId(),
                voiceprintConfig.getApiSecret(),
                voiceprintConfig.getApiKey(),
                params
            );
            
            Map<String, Object> result = parseResponse(response);
            log.info("创建特征库完成，结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("创建特征库失败", e);
            throw new RuntimeException("创建特征库失败: " + e.getMessage(), e);
        }
    }

    /**
     * 添加音频特征（使用Base64数据）
     * 
     * @param groupId 组ID
     * @param featureId 特征ID
     * @param featureInfo 特征信息
     * @param audioBase64 音频Base64数据
     * @return 添加结果
     */
    public Map<String, Object> addAudioFeature(String groupId, String featureId, String featureInfo, String audioBase64) {
        try {
            // 兼容前端传入的 data:audio/...;base64, 前缀，同时在移除前缀前先判断资源编码
            String original = audioBase64;
            String resourceEncoding = audioUtil.detectResourceEncodingByDataUrl(original);
            int[] wavMeta = audioUtil.detectWavMetaFromBase64(original);
            if (wavMeta != null) { resourceEncoding = "raw"; }
            audioBase64 = audioUtil.stripDataUrlPrefix(audioBase64);
            if ("raw".equalsIgnoreCase(resourceEncoding)) {
                audioBase64 = audioUtil.normalizeBase64ForEncoding(audioBase64, resourceEncoding);
            }
            int sampleRate = 16000, channels = 1, bitDepth = 16;
            if (wavMeta != null) { sampleRate = wavMeta[0]; channels = wavMeta[1]; bitDepth = wavMeta[2]; }
            // 若为raw且采样参数非16k/1/16，则进行强制重采样与通道/位深转换
            if ("raw".equalsIgnoreCase(resourceEncoding) && wavMeta != null && (sampleRate != 16000 || channels != 1 || bitDepth != 16)) {
                audioBase64 = audioUtil.ensurePcm16kMono16bitBase64(audioBase64, sampleRate, channels, bitDepth);
                sampleRate = 16000; channels = 1; bitDepth = 16;
                log.info("已对PCM进行规范化到16k/1/16");
            }
            log.info("开始添加音频特征，组ID: {}, 特征ID: {}, sr/ch/bd={}/{}/{}", groupId, featureId, sampleRate, channels, bitDepth);
            
            return addAudioFeatureInternal(groupId, featureId, featureInfo, audioBase64, resourceEncoding, sampleRate, channels, bitDepth);
        } catch (Exception e) {
            log.error("添加音频特征失败", e);
            throw new RuntimeException("添加音频特征失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 添加音频特征（使用文件上传）
     * 
     * @param groupId 组ID
     * @param featureId 特征ID
     * @param featureInfo 特征信息
     * @param audioFile 音频文件
     * @return 添加结果
     */
     public Map<String, Object> addAudioFeature(String groupId, String featureId, String featureInfo, MultipartFile audioFile) {
         try {
             log.info("开始添加音频特征（文件上传），组ID: {}, 特征ID: {}, 文件: {}", 
                     groupId, featureId, audioFile.getOriginalFilename());
             
             // 依据文件扩展名推断resource.encoding
             String resourceEncoding = audioUtil.detectResourceEncodingByFilename(audioFile.getOriginalFilename());
             int[] wavMeta = null;
             try { wavMeta = audioUtil.detectWavMetaFromMultipartFile(audioFile); } catch (IOException ignore) {}
             
             // 将文件转换为Base64（内部已对WAV尝试提取PCM）
             String audioBase64 = audioUtil.multipartFileToBase64(audioFile);
             int sampleRate = 16000, channels = 1, bitDepth = 16;
             if (wavMeta != null) { sampleRate = wavMeta[0]; channels = wavMeta[1]; bitDepth = wavMeta[2]; }
             // 若为raw且采样参数非16k/1/16，则进行强制重采样与通道/位深转换
             if ("raw".equalsIgnoreCase(resourceEncoding) && wavMeta != null && (sampleRate != 16000 || channels != 1 || bitDepth != 16)) {
                 audioBase64 = audioUtil.ensurePcm16kMono16bitBase64(audioBase64, sampleRate, channels, bitDepth);
                 sampleRate = 16000; channels = 1; bitDepth = 16;
                 log.info("已对PCM(文件)进行规范化到16k/1/16");
             }
             
             return addAudioFeatureInternal(groupId, featureId, featureInfo, audioBase64, resourceEncoding, sampleRate, channels, bitDepth);
         } catch (Exception e) {
             log.error("添加音频特征失败（文件上传）", e);
             throw new RuntimeException("添加音频特征失败: " + e.getMessage(), e);
         }
     }
     
     // 新增：内部通用实现，统一发送请求并打印参数（包含sr/ch/bd）
     private Map<String, Object> addAudioFeatureInternal(String groupId, String featureId, String featureInfo, String audioBase64, String resourceEncoding, int sampleRate, int channels, int bitDepth) {
         try {
             String params = buildCreateFeatureParams(groupId, featureId, featureInfo, audioBase64, resourceEncoding, sampleRate, channels, bitDepth);
             // 按用户要求，输出完整请求体日志
             log.info("params=>{}", params);
             String response = httpUtil.doPost(
                 voiceprintConfig.getRequestUrl(),
                 voiceprintConfig.getAppId(),
                 voiceprintConfig.getApiSecret(),
                 voiceprintConfig.getApiKey(),
                 params
             );
             
             Map<String, Object> result = parseResponse(response);
             log.info("添加音频特征完成，结果: {}", result);
             return result;
         } catch (Exception e) {
             log.error("添加音频特征内部处理失败", e);
             throw new RuntimeException("添加音频特征失败: " + e.getMessage(), e);
         }
     }
    /**
     * 创建音频特征（原方法保持兼容性）
     * 
     * @param audioBase64 音频Base64编码
     * @param featureId 特征ID
     * @param groupId 组ID
     * @return 添加结果
     */
     public String createFeature(String audioBase64, String featureId, String groupId) {
         try {
             // 兼容前端传入的 data:audio/...;base64, 前缀；在移除前缀前进行encoding判断
             String original = audioBase64;
             String resourceEncoding = audioUtil.detectResourceEncodingByDataUrl(original);
             int[] wavMeta = audioUtil.detectWavMetaFromBase64(original);
             if (wavMeta != null) { resourceEncoding = "raw"; }
             audioBase64 = audioUtil.stripDataUrlPrefix(audioBase64);
             if ("raw".equalsIgnoreCase(resourceEncoding)) {
                 audioBase64 = audioUtil.normalizeBase64ForEncoding(audioBase64, resourceEncoding);
             }
             int sampleRate = 16000, channels = 1, bitDepth = 16;
             if (wavMeta != null) { sampleRate = wavMeta[0]; channels = wavMeta[1]; bitDepth = wavMeta[2]; }
             // 若为raw且采样参数非16k/1/16，则进行强制重采样与通道/位深转换
             if ("raw".equalsIgnoreCase(resourceEncoding) && wavMeta != null && (sampleRate != 16000 || channels != 1 || bitDepth != 16)) {
                 audioBase64 = audioUtil.ensurePcm16kMono16bitBase64(audioBase64, sampleRate, channels, bitDepth);
                 sampleRate = 16000; channels = 1; bitDepth = 16;
                 log.info("已对PCM进行规范化到16k/1/16(createFeature)");
             }
             log.info("开始添加音频特征，featureId: {}, groupId: {}, sr/ch/bd={}/{}/{}", featureId, groupId, sampleRate, channels, bitDepth);
             
             String requestUrl = buildRequestUrl("createFeature");
             String params = buildCreateFeatureParams(audioBase64, featureId, groupId, resourceEncoding, sampleRate, channels, bitDepth);
             log.info("params=>{}", params);
             
             String response = doHttpRequest(requestUrl, params);
             log.info("添加音频特征响应: {}", response);
             
             return parseResponse(response, "createFeatureRes");
         } catch (Exception e) {
             log.error("添加音频特征失败", e);
             throw new RuntimeException("添加音频特征失败: " + e.getMessage());
         }
     }

    /**
     * 1:1声纹比对（使用Base64数据）
     * 
     * @param groupId 组ID
     * @param featureId 特征ID
     * @param audioBase64 音频Base64数据
     * @return 比对结果
     */
    public Map<String, Object> searchOneFeature(String groupId, String featureId, String audioBase64) {
        try {
            log.info("开始1:1声纹比对，组ID: {}, 特征ID: {}", groupId, featureId);
            // 兼容前端传入的 data:audio/...;base64, 前缀；在移除前先判断资源编码
            String original = audioBase64;
            String resourceEncoding = audioUtil.detectResourceEncodingByDataUrl(original);
            int[] wavMeta = audioUtil.detectWavMetaFromBase64(original);
            if (wavMeta != null) { resourceEncoding = "raw"; }
            audioBase64 = audioUtil.stripDataUrlPrefix(audioBase64);
            if ("raw".equalsIgnoreCase(resourceEncoding)) {
                audioBase64 = audioUtil.normalizeBase64ForEncoding(audioBase64, resourceEncoding);
            }
            int sampleRate = 16000, channels = 1, bitDepth = 16;
            if (wavMeta != null) { sampleRate = wavMeta[0]; channels = wavMeta[1]; bitDepth = wavMeta[2]; }
            // 若为raw且采样参数非16k/1/16，则进行强制重采样与通道/位深转换
            if ("raw".equalsIgnoreCase(resourceEncoding) && wavMeta != null && (sampleRate != 16000 || channels != 1 || bitDepth != 16)) {
                audioBase64 = audioUtil.ensurePcm16kMono16bitBase64(audioBase64, sampleRate, channels, bitDepth);
                sampleRate = 16000; channels = 1; bitDepth = 16;
                log.info("已对PCM进行规范化到16k/1/16");
            }
            String params = buildSearchOneFeatureParams(audioBase64, featureId, groupId, resourceEncoding, sampleRate, channels, bitDepth);
            log.info("params=>{}", params);
            String response = httpUtil.doPost(
                voiceprintConfig.getRequestUrl(),
                voiceprintConfig.getAppId(),
                voiceprintConfig.getApiSecret(),
                voiceprintConfig.getApiKey(),
                params
            );
            Map<String, Object> result = parseResponse(response);
            log.info("1:1声纹比对完成，结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("1:1声纹比对失败", e);
            throw new RuntimeException("1:1声纹比对失败: " + e.getMessage(), e);
        }
    }

    /**
     * 1:1声纹比对（使用文件上传）
     * 
     * @param groupId 组ID
     * @param featureId 特征ID
     * @param audioFile 音频文件
     * @return 比对结果
     */
    public Map<String, Object> searchOneFeature(String groupId, String featureId, MultipartFile audioFile) {
        try {
            log.info("开始1:1声纹比对（文件上传），组ID: {}, 特征ID: {}, 文件: {}", 
                    groupId, featureId, audioFile.getOriginalFilename());
            
            // 将文件转换为Base64
            String audioBase64 = audioUtil.convertToBase64(audioFile);
            
            return searchOneFeature(groupId, featureId, audioBase64);
        } catch (Exception e) {
            log.error("1:1声纹比对失败（文件上传）", e);
            throw new RuntimeException("1:1声纹比对失败: " + e.getMessage(), e);
        }
    }

    /**
     * 1:N声纹搜索（使用Base64数据）
     * 
     * @param groupId 组ID
     * @param audioBase64 音频Base64数据
     * @return 搜索结果
     */
    public Map<String, Object> searchFeature(String groupId, String audioBase64) {
        try {
            // 兼容前端传入的 data:audio/...;base64, 前缀
            audioBase64 = audioUtil.stripDataUrlPrefix(audioBase64);
            log.info("开始1:N声纹搜索，组ID: {}", groupId);
            
            String params = buildSearchFeatureParams(audioBase64, groupId);
            log.info("params=>{}", params);
            String response = httpUtil.doPost(
                voiceprintConfig.getRequestUrl(),
                voiceprintConfig.getAppId(),
                voiceprintConfig.getApiSecret(),
                voiceprintConfig.getApiKey(),
                params
            );
            Map<String, Object> result = parseResponse(response);
            log.info("1:N声纹搜索完成，结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("1:N声纹搜索失败", e);
            throw new RuntimeException("1:N声纹搜索失败: " + e.getMessage(), e);
        }
    }

    /**
     * 1:N声纹搜索（使用文件上传）
     * 
     * @param groupId 组ID
     * @param audioFile 音频文件
     * @return 搜索结果
     */
    public Map<String, Object> searchFeature(String groupId, MultipartFile audioFile) {
        try {
            log.info("开始1:N声纹搜索（文件上传），组ID: {}, 文件: {}", 
                    groupId, audioFile.getOriginalFilename());
            
            // 将文件转换为Base64
            String audioBase64 = audioUtil.convertToBase64(audioFile);
            
            return searchFeature(groupId, audioBase64);
        } catch (Exception e) {
            log.error("1:N声纹搜索失败（文件上传）", e);
            throw new RuntimeException("1:N声纹搜索失败: " + e.getMessage(), e);
        }
    }

    /**
     * 删除声纹特征
     * 
     * @param groupId 组ID
     * @param featureId 特征ID
     * @return 删除结果
     */
    public Map<String, Object> deleteFeature(String groupId, String featureId) {
        try {
            log.info("开始删除声纹特征，组ID: {}, 特征ID: {}", groupId, featureId);
            
            String params = buildDeleteFeatureParams(featureId, groupId);
             log.info("params=>{}", params);
             String response = httpUtil.doPost(
                 voiceprintConfig.getRequestUrl(),
                 voiceprintConfig.getAppId(),
                 voiceprintConfig.getApiSecret(),
                 voiceprintConfig.getApiKey(),
                 params
             );
            
            Map<String, Object> result = parseResponse(response);
            log.info("删除声纹特征完成，结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("删除声纹特征失败", e);
            throw new RuntimeException("删除声纹特征失败: " + e.getMessage(), e);
        }
    }

    /**
     * 声纹识别1:1比对（原方法保持兼容性）
     * 
     * @param audioBase64 音频Base64编码
     * @param featureId 特征ID
     * @param groupId 组ID
     * @return 比对结果
     */
    public String searchOneFeatureCompat(String audioBase64, String featureId, String groupId) {
        try {
            // 兼容前端传入的 data:audio/...;base64, 前缀
            audioBase64 = audioUtil.stripDataUrlPrefix(audioBase64);
            log.info("开始声纹识别1:1比对，featureId: {}, groupId: {}", featureId, groupId);
            
            String requestUrl = buildRequestUrl("searchOneFeature");
            String params = buildSearchOneFeatureParams(audioBase64, featureId, groupId);
            
            String response = doHttpRequest(requestUrl, params);
            log.info("声纹识别1:1比对响应: {}", response);
            
            return parseResponse(response, "searchScoreFeaRes");
        } catch (Exception e) {
            log.error("声纹识别1:1比对失败", e);
            throw new RuntimeException("声纹识别1:1比对失败: " + e.getMessage());
        }
    }

    /**
     * 声纹识别1:N比对（原方法保持兼容性）
     * 
     * @param audioBase64 音频Base64编码
     * @param groupId 组ID
     * @return 比对结果
     */
    public String searchFeatureCompat(String audioBase64, String groupId) {
        try {
            // 向后兼容：默认按lame编码，16k/1/16
            return buildSearchFeatureParams(audioBase64, groupId, "lame", 16000, 1, 16);
        } catch (Exception e) {
            log.error("声纹识别1:N比对失败", e);
            throw new RuntimeException("声纹识别1:N比对失败: " + e.getMessage());
        }
    }

    /**
     * 删除指定特征（原方法保持兼容性）
     * 
     * @param featureId 特征ID
     * @param groupId 组ID
     * @return 删除结果
     */
    public String deleteFeatureCompat(String featureId, String groupId) {
        try {
            log.info("开始删除指定特征，featureId: {}, groupId: {}", featureId, groupId);
            
            String requestUrl = buildRequestUrl("deleteFeature");
            String params = buildDeleteFeatureParams(featureId, groupId);
            
            String response = doHttpRequest(requestUrl, params);
            log.info("删除指定特征响应: {}", response);
            
            return parseResponse(response, "deleteFeatureRes");
        } catch (Exception e) {
            log.error("删除指定特征失败", e);
            throw new RuntimeException("删除指定特征失败: " + e.getMessage());
        }
    }

    /**
     * 构建请求URL
     */
    private String buildRequestUrl(String action) {
        try {
            String httpRequestUrl = voiceprintConfig.getRequestUrl().replace("ws://", "http://").replace("wss://", "https://");
            URL url = new URL(httpRequestUrl);
            
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());
            
            String host = url.getHost();
            String path = url.getPath();
            
            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n");
            builder.append("date: ").append(date).append("\n");
            builder.append("POST ").append(path).append(" HTTP/1.1");
            
            String sha = hmacsign(builder.toString(), voiceprintConfig.getApiSecret());
            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                    voiceprintConfig.getApiKey(), "hmac-sha256", "host date request-line", sha);
            
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8));
            
            return String.format("%s?authorization=%s&host=%s&date=%s",
                    httpRequestUrl,
                    URLEncoder.encode(authBase, "UTF-8"),
                    URLEncoder.encode(host, "UTF-8"),
                    URLEncoder.encode(date, "UTF-8"));
        } catch (Exception e) {
            throw new RuntimeException("构建请求URL失败", e);
        }
    }

    /**
     * HMAC-SHA256签名
     */
    private String hmacsign(String signature, String apiSecret) throws Exception {
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(signature.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hexDigits);
    }

    /**
     * 执行HTTP请求
     */
    private String doHttpRequest(String requestUrl, String params) throws Exception {
        URL realUrl = new URL(requestUrl);
        URLConnection connection = realUrl.openConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
        httpURLConnection.setDoInput(true);
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setRequestProperty("Content-type", "application/json");
        httpURLConnection.setConnectTimeout(voiceprintConfig.getTimeoutSeconds() * 1000);
        httpURLConnection.setReadTimeout(voiceprintConfig.getTimeoutSeconds() * 1000);

        try (OutputStream out = httpURLConnection.getOutputStream()) {
            out.write(params.getBytes(StandardCharsets.UTF_8));
            out.flush();
        }

        InputStream is;
        try {
            is = httpURLConnection.getInputStream();
        } catch (Exception e) {
            is = httpURLConnection.getErrorStream();
            String errorResponse = readAllBytes(is);
            throw new Exception("HTTP请求失败: " + httpURLConnection.getResponseCode() + " " + httpURLConnection.getResponseMessage() + ", " + errorResponse);
        }
        
        return readAllBytes(is);
    }

    /**
     * 读取输入流内容
     */
    private String readAllBytes(InputStream is) throws IOException {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            return result.toString();
        }
    }

    /**
     * 解析响应结果
     */
    private String parseResponse(String response, String responseType) {
        try {
            JSONObject jsonResponse = JSON.parseObject(response);
            JSONObject payload = jsonResponse.getJSONObject("payload");
            JSONObject responseData = payload.getJSONObject(responseType);
            String textBase64 = responseData.getString("text");
            
            String decodedText = new String(Base64.getDecoder().decode(textBase64), StandardCharsets.UTF_8);
            return decodedText;
        } catch (Exception e) {
            log.error("解析响应失败: {}", response, e);
            throw new RuntimeException("解析响应失败: " + e.getMessage());
        }
    }

    /**
     * 构建创建组参数 - JSON格式
     */
    private String buildCreateGroupParams(String groupId) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"createGroup\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"groupName\": \"" + groupId + "_name\"," +
                "\"groupInfo\": \"声纹识别特征库\"," +
                "\"createGroupRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}" +
                "}";
    }
    
    /**
     * 构建创建特征参数 - JSON格式
     */
    private String buildCreateFeatureParams(String audioBase64, String featureId, String groupId, String resourceEncoding) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"createFeature\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"featureId\": \"" + featureId + "\"," +
                "\"createFeatureRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}," +
                "\"payload\": {" +
                "\"resource\": {" +
                "\"encoding\": \"" + resourceEncoding + "\"," +
                "\"sample_rate\": 16000," +
                "\"channels\": 1," +
                "\"bit_depth\": 16," +
                "\"status\": 3," +
                "\"audio\": \"" + audioBase64 + "\"" +
                "}" +
                "}" +
                "}";
    }
    
    // 动态设置采样参数的重载（无featureInfo）
    private String buildCreateFeatureParams(String audioBase64, String featureId, String groupId, String resourceEncoding, int sampleRate, int channels, int bitDepth) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"createFeature\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"featureId\": \"" + featureId + "\"," +
                "\"createFeatureRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}," +
                "\"payload\": {" +
                "\"resource\": {" +
                "\"encoding\": \"" + resourceEncoding + "\"," +
                "\"sample_rate\": " + sampleRate + "," +
                "\"channels\": " + channels + "," +
                "\"bit_depth\": " + bitDepth + "," +
                "\"status\": 3," +
                "\"audio\": \"" + audioBase64 + "\"" +
                "}" +
                "}" +
                "}";
    }
    
    private String buildCreateFeatureParams(String groupId, String featureId, String featureInfo, String audioBase64, String resourceEncoding) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"createFeature\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"featureId\": \"" + featureId + "\"," +
                "\"featureInfo\": \"" + featureInfo + "\"," +
                "\"createFeatureRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}," +
                "\"payload\": {" +
                "\"resource\": {" +
                "\"encoding\": \"" + resourceEncoding + "\"," +
                "\"sample_rate\": 16000," +
                "\"channels\": 1," +
                "\"bit_depth\": 16," +
                "\"status\": 3," +
                "\"audio\": \"" + audioBase64 + "\"" +
                "}" +
                "}" +
                "}";
    }
    
    // 动态设置采样参数的重载（带featureInfo）
    private String buildCreateFeatureParams(String groupId, String featureId, String featureInfo, String audioBase64, String resourceEncoding, int sampleRate, int channels, int bitDepth) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"createFeature\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"featureId\": \"" + featureId + "\"," +
                "\"featureInfo\": \"" + featureInfo + "\"," +
                "\"createFeatureRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}," +
                "\"payload\": {" +
                "\"resource\": {" +
                "\"encoding\": \"" + resourceEncoding + "\"," +
                "\"sample_rate\": " + sampleRate + "," +
                "\"channels\": " + channels + "," +
                "\"bit_depth\": " + bitDepth + "," +
                "\"status\": 3," +
                "\"audio\": \"" + audioBase64 + "\"" +
                "}" +
                "}" +
                "}";
    }
    
    /**
     * 构建1:1声纹比对参数 - JSON格式
     */
    private String buildSearchOneFeatureParams(String audioBase64, String featureId, String groupId) {
        // 向后兼容：默认按lame编码，16k/1/16
        return buildSearchOneFeatureParams(audioBase64, featureId, groupId, "lame", 16000, 1, 16);
    }
    
    /**
     * 构建1:1声纹比对参数 - JSON格式
     */
    private String buildSearchOneFeatureParams(String audioBase64, String featureId, String groupId, String resourceEncoding, int sampleRate, int channels, int bitDepth) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"searchScoreFea\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"dstFeatureId\": \"" + featureId + "\"," +
                "\"searchScoreFeaRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}," +
                "\"payload\": {" +
                "\"resource\": {" +
                "\"encoding\": \"" + resourceEncoding + "\"," +
                "\"sample_rate\": " + sampleRate + "," +
                "\"channels\": " + channels + "," +
                "\"bit_depth\": " + bitDepth + "," +
                "\"status\": 3," +
                "\"audio\": \"" + audioBase64 + "\"" +
                "}" +
                "}" +
                "}";
    }
    
    /**
     * 构建1:N声纹比对参数 - JSON格式
     */
    private String buildSearchFeatureParams(String audioBase64, String groupId) {
        // 向后兼容：默认按lame编码，16k/1/16
        return buildSearchFeatureParams(audioBase64, groupId, "lame", 16000, 1, 16);
    }
    
    // 新增：支持动态编码与采样参数的1:N构建
    private String buildSearchFeatureParams(String audioBase64, String groupId, String resourceEncoding, int sampleRate, int channels, int bitDepth) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"searchFea\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"searchFeaRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}," +
                "\"payload\": {" +
                "\"resource\": {" +
                "\"encoding\": \"" + resourceEncoding + "\"," +
                "\"sample_rate\": " + sampleRate + "," +
                "\"channels\": " + channels + "," +
                "\"bit_depth\": " + bitDepth + "," +
                "\"status\": 3," +
                "\"audio\": \"" + audioBase64 + "\"" +
                "}" +
                "}" +
                "}";
    }
    
    /**
     * 构建删除特征参数 - JSON格式
     */
    private String buildDeleteFeatureParams(String featureId, String groupId) {
        return "{" +
                "\"header\": {" +
                "\"app_id\": \"" + voiceprintConfig.getAppId() + "\"," +
                "\"status\": 3" +
                "}," +
                "\"parameter\": {" +
                "\"s782b4996\": {" +
                "\"func\": \"deleteFeature\"," +
                "\"groupId\": \"" + groupId + "\"," +
                "\"featureId\": \"" + featureId + "\"," +
                "\"deleteFeatureRes\": {" +
                "\"encoding\": \"utf8\"," +
                "\"compress\": \"raw\"," +
                "\"format\": \"json\"" +
                "}" +
                "}" +
                "}" +
                "}";
    }
    
    /**
     * 解析API响应（新方法）
     */
    private Map<String, Object> parseResponse(String response) {
        try {
            JSONObject jsonResponse = JSON.parseObject(response);
            Map<String, Object> result = new HashMap<>();
            
            // 解析header
            JSONObject header = jsonResponse.getJSONObject("header");
            if (header != null) {
                result.put("code", header.getInteger("code"));
                result.put("message", header.getString("message"));
                result.put("sid", header.getString("sid"));
                result.put("status", header.getInteger("status"));
            }
            
            // 解析payload
            JSONObject payload = jsonResponse.getJSONObject("payload");
            if (payload != null) {
                // 尝试解析不同类型的响应
                for (String key : payload.keySet()) {
                    JSONObject responseData = payload.getJSONObject(key);
                    if (responseData != null && responseData.containsKey("text")) {
                        String textBase64 = responseData.getString("text");
                        try {
                            String decodedText = new String(Base64.getDecoder().decode(textBase64), "UTF-8");
                            JSONObject decodedJson = JSON.parseObject(decodedText);
                            result.put("data", decodedJson);
                        } catch (Exception e) {
                            log.warn("解析Base64文本失败: {}", e.getMessage());
                            result.put("rawText", textBase64);
                        }
                    }
                }
            }
            
            return result;
        } catch (Exception e) {
            log.error("解析响应失败: {}", response, e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("code", -1);
            errorResult.put("message", "响应解析失败: " + e.getMessage());
            errorResult.put("rawResponse", response);
            return errorResult;
        }
    }
}